package com.wsh.shop.common.dao.impl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import com.wsh.shop.common.util.ConstatFinalUtil;
import com.wsh.shop.common.util.DbUtil;
import com.wsh.shop.common.util.PageInfoUtil;

/**
 * 此类是所有Dao的公共类
 * 
 * T:表示泛型,在父类我不知道dao对应的是哪张表,想在父类里面使用某个类型(不定的)的对象,那就加T,(占位符)
 * 让子类来确定哪张表的Dao
 * T:暂时理解为Object,在使用的时候,根据指定的类型来确定T的类型;
 * 在父类里面不能出现子类相关的类型
 * 
 * @author wangshMac
 */
public class BaseDaoImpl<T>
{
	/* 加载驱动和获取链接 */
	protected DbUtil dbUtil = DbUtil.getInstance() ; 
	
	/**
	 * 把数据库里面的记录,变成java的对象
	 * 利用反射
	 * 
	 * ~将返回值由Admins换成了Object
	 * ~增加了一个参数:Object,参数的Object和返回值一样;
	 * 
	 * 在调用处的时候,传上Dao对应的类型
	 * 
	 * @param rs
	 * @return
	 * @throws SQLException
	 */
	protected T convertFromDb(T t,ResultSet rs) throws SQLException
	{
		/*
		 * ~获取Class对象
		 * ~获取所有的method 
		 * */
		Class cla = t.getClass() ; 
		/* new一个对象
				 * 所有的属性全部是空的,
				 * 调用set方法赋值
				 *  */
		Object returnObj = null;
		try
		{
			returnObj = cla.newInstance();
		} catch (InstantiationException e1)
		{
			e1.printStackTrace();
		} catch (IllegalAccessException e1)
		{
			e1.printStackTrace();
		}
		
		/* 获取所有的字段 */
		Field[] fields = cla.getDeclaredFields() ; 
		for (int i = 0; i < fields.length; i++)
		{
			try
			{
				Field field = fields[i];
				/* 字段名 */
				String name = field.getName() ; 
				/*
				 * id = Id;
				 * setId ;
				 * */
				String setName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1,name.length());
				/*
				 * field.getType():获取属性的类型,
				 * 返回值是Class
				 * */
				//System.out.println(i + "===" + name + "--->" + setName + "--->" + field.getType().getSimpleName());
				Class fieldTypeClass = field.getType() ; 
				/* set方法
				 * setName
				 * 
				 * getMethod
				 * 参数1:指的是方法名;set+属性(首字母大写)
				 * 参数2:类型;有int,byte,string,Date
				 * 有待扩展,有可能填写Double,四类八种,都考虑到
				 *  */
				Method setMethod = null ; 
				/* 从数据库中取值
				 * POJO中的属性名和表的列名一样,
				 * 
				 * 如果是int,调用rs.getInt
				 * 如果是byte,调用rs.getByte()
				 * 
				 * dbObj = rs.getInt(name);
				 *  */
				Object dbObj = null ; 
				if(fieldTypeClass == int.class || fieldTypeClass == Integer.class)
				{
					setMethod = cla.getMethod(setName, int.class);
					dbObj = rs.getInt(name);
				}else if(fieldTypeClass == byte.class || fieldTypeClass == Byte.class)
				{
					setMethod = cla.getMethod(setName, byte.class);
					dbObj = rs.getByte(name);
				}else if(fieldTypeClass == double.class || fieldTypeClass == Double.class)
				{
					setMethod = cla.getMethod(setName, double.class);
					dbObj = rs.getDouble(name);
				}else if(fieldTypeClass == String.class)
				{
					setMethod = cla.getMethod(setName, String.class);
					dbObj = rs.getString(name);
				}else if(fieldTypeClass == Date.class)
				{
					setMethod = cla.getMethod(setName, Date.class);
					dbObj = rs.getTimestamp(name);
				}
				
				if(setMethod != null)
				{
					/* 执行setMethod
					 * setName("测试");的参数是赋值,要从数据库中取
					 * 
					 * 参数1:是对象,Class对应的对象
					 * 参数2:方法的形参对应的实参;
					 * setName方法可是木有返回值
					 *  */
					setMethod.invoke(returnObj, dbObj);
				}
			} catch (Exception e)
			{
				//e.printStackTrace();
			}
		}
		return (T) returnObj; 
	}
	
	/**
	 * 父类中查询一条记录
	 */
	protected T findOneBase(String sql,List<Object> paramsList,T t)
	{
		/*-----------------标准的JDBC-------------------*/
		PreparedStatement ps = null ;
		ResultSet rs = null ; 
		Connection connection = this.dbUtil.getConnection() ; 
		try
		{
			ps = connection.prepareStatement(sql);
			/* 设置条件
			 * 从Map中取值的时候,使用的时候好大方,好气场,一定确定一下有木有放进去(四大作用域)
			 * 
			 * 参数1:第几个?
			 * 参数2:为第几个?赋值
			 *  */
			//ps.setObject(1, condMap.get("id"));
			/* 有多少个?,就要设置多个条件 */
			int count = 1 ; 
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object paramObj = (Object) iterator.next();
				ps.setObject(count, paramObj);
				/* 计数器 */
				count ++ ; 
			}
			
			rs = ps.executeQuery();
			/* 如果是多条,使用循环
			 * 如果是单条,使用判断 */
			if(rs.next())
			{
				/* 将数据库里面的记录变成JAVA对象 */
				t = convertFromDb(t , rs);
				return t ; 
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		}finally
		{
			this.dbUtil.closeAll(connection, ps, rs);
		}
		return null ; 
	}
	
	/**
	 * 查询列表,不分页
	 * @return
	 */
	protected List<T> find(String sql,List<Object> paramList,T t)
	{
		/*-----------------标准的JDBC-------------------*/
		List<T> resultList = new ArrayList<T>();
		
		PreparedStatement ps = null ;
		ResultSet rs = null ; 
		Connection connection = this.dbUtil.getConnection() ; 
		try
		{
			/* 查询所有数据 */
			ps = connection.prepareStatement(sql);
			/* 设置条件 */
			int count = 1 ; 
			for (Iterator iterator = paramList.iterator(); iterator.hasNext();)
			{
				Object paramObj = (Object) iterator.next();
				ps.setObject(count, paramObj);
				count ++ ; 
			}
			rs = ps.executeQuery();
			
			/* 如果是多条,使用循环
			 * 如果是单条,使用判断 */
			while(rs.next())
			{
				/* 将数据库里面的记录变成JAVA对象 */
				t = this.convertFromDb(t, rs);
				/* 把admins放到集合中 */
				resultList.add(t);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		}finally
		{
			this.dbUtil.closeAll(connection, ps, rs);
		}
		return resultList;
	}

	/**
	 * 查询列表,分页
	 * @return
	 */
	protected List<T> findByPage(PageInfoUtil pageInfoUtil, String sql,List<Object> paramList,T t)
	{
		/*-----------------标准的JDBC-------------------*/
		List<T> resultList = new ArrayList<T>();
		PreparedStatement ps = null ;
		ResultSet rs = null ; 
		Connection connection = this.dbUtil.getConnection() ; 
		try
		{
			if(pageInfoUtil != null)
			{
				String fromIndex = "from" ; 
				String orderbyIndex = "order by" ; 
				String countSQL = "select count(*) " + sql.substring( sql.indexOf(fromIndex) , sql.indexOf(orderbyIndex));
				ConstatFinalUtil.SYS_LOGGER.info("==总条数sql:{}==" , countSQL);
				ConstatFinalUtil.SYS_LOGGER.info("==总条数条件:{}==" , paramList);
				/* 将sql语句发送到数据库 */
				ps = connection.prepareStatement(countSQL);
				/* 设置条件 */
				int count = 1 ; 
				for (Iterator iterator = paramList.iterator(); iterator.hasNext();)
				{
					Object paramObj = (Object) iterator.next();
					ps.setObject(count, paramObj);
					count ++ ; 
				}
				rs = ps.executeQuery();
				/* 总记录数,肯定有一条结果 */
				if(rs.next())
				{
					/* 取第一列 */
					int totalRecord = rs.getInt(1);
					pageInfoUtil.setTotalRecord(totalRecord);
				}
				rs.close();
				ps.close();
				
				/* select * from a_admins limit 1,5*/
				sql = sql + " limit ? , ? ";
				/* 查询分页数据 */
				/*ps = connection.prepareStatement(sql);
				 设置条件 
				ps.setObject(1, pageInfoUtil.getCurrentRecord());
				ps.setObject(2, pageInfoUtil.getPageSize());
				rs = ps.executeQuery();*/
				
				/* 把条件统一放到List中 */
				paramList.add(pageInfoUtil.getCurrRecord());
				paramList.add(pageInfoUtil.getPageSize());
				
				ConstatFinalUtil.SYS_LOGGER.info("==取数据sql:{}==" , sql);
				ConstatFinalUtil.SYS_LOGGER.info("==取数据条件:{}==" , paramList);
			}
			
			/* 查询所有数据 */
			ps = connection.prepareStatement(sql);
			/* 设置条件 */
			int count = 1 ; 
			for (Iterator iterator = paramList.iterator(); iterator.hasNext();)
			{
				Object paramObj = (Object) iterator.next();
				ps.setObject(count, paramObj);
				count ++ ; 
			}
			rs = ps.executeQuery();
			
			/* 如果是多条,使用循环
			 * 如果是单条,使用判断 */
			while(rs.next())
			{
				/* 将数据库里面的记录变成JAVA对象 */
				t = this.convertFromDb(t, rs);
				/* 把admins放到集合中 */
				resultList.add(t);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		}finally
		{
			this.dbUtil.closeAll(connection, ps, rs);
		}
		return resultList;
	}
	
	/**
	 * 执行一条sql语句
	 */
	protected int executeSqlUpdate(String sql,List<Object> paramsList)
	{
		/*-------JDBC------*/
		int res = 0 ; 
		Connection connection = this.dbUtil.getConnection() ; 
		PreparedStatement ps = null ; 
		ResultSet rs = null ; 
		try
		{
			ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
			/* 设置条件 */
			int parameterIndex = 1 ; 
			for (Iterator iterator = paramsList.iterator(); iterator.hasNext();)
			{
				Object paramObj = (Object) iterator.next();
				ps.setObject(parameterIndex, paramObj);
				parameterIndex ++ ; 
			}
			/*
			 * 返回值:res的含义是:执行sql语句以后对数据库影响的条数
			 * */
			res = ps.executeUpdate();
			
			/* 获取主键 */
			rs = ps.getGeneratedKeys() ; 
			if(rs.next())
			{
				int id = rs.getInt(1);
				/* 保存方法执行的结果时,要么使用返回值,要么参数返回 */
				paramsList.add(id);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		}finally
		{
			this.dbUtil.closeAll(connection, ps, rs);
		}
		return res;
	}
}
